package org.opens.lambda;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.DoubleToIntFunction;
import java.util.function.Supplier;

public class TypeInference {

    static interface LambdaTest {

        public int square(int x);

        public int minusOne(int x);

    }

    /**
     *
     */
    @Test
    public void test() {
        LambdaTest lambdaTest = new TypeInference.LambdaTest() {
            @Override
            public int square(int x) {
                return x * x;
            }

            @Override
            public int minusOne(int x) {
                return x - 1;
            }
        };
        System.out.println(lambdaTest.square(2));
        System.out.println(lambdaTest.minusOne(2));
    }

    @Test
    public void test2() {
        DoubleToIntFunction function = (DoubleToIntFunction) (x) -> {
            return (int) (x * x);
        };
        System.out.println(function.applyAsInt(20));
    }

    /**
     * 说明:
     *      1. 这两种方式都可以定义Lambda表达式, 只不过function1的方式是声明了参数类型, function2看起来像是没有声明参数类型;
     *          - 其实并不是没有声明, 而是根据java的一个特性: 类型推断, 而省略了类型声明, 所以lambda也没有打破java是静态强类型语言.
     *      2. Function是一个函数式接口, 它有两个泛型, 其实在函数式编程中, 还有两种函数式接口:
     *          - Function
     *              这种函数模型表示有一个函数入口, 一个函数出口, 也就是有参数也有返回值;
     *          - Predicate
     *              这种函数模型表示有函数入口, 但是函数出口被限定为true/false.
     *          - Supplier
     *              这种函数模型表示没有函数入口, 会返回一个对象.
     */
    @Test
    public void test3() {
        Function<Integer, Integer> function1 = (Integer x) -> x * x;
        Function<Integer, Integer> function2 = (x) -> x * x;
        Predicate<Integer> tPredicate = (x) -> x > 2;
        System.out.println(function1.apply(20));
        System.out.println(function2.apply(20));
    }

    /**
     * 说明:
     *      1. 这相当于创建了Consumer接口的匿名对象;
     *          - 查看forEach的源码, 就会发现, 其实是直接调用了这个接口的方法, 相当于最终是使用了多态来实现了.
     *          - 现在, 我们可以使用java8的lambda特性优化一下语法, 使语法更加简洁(其实还是使用了java的另一个特性: 类型推断)
     *      2. Consumer的中文意思为: 消费者, 在函数式接口中, 该接口用来描述"只接受参数, 不返回参数的行为".
     */
    @Test
    public void test4() {
        List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
        list.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });
        list.forEach(x -> System.out.println(x));
        //直接进行方法引用, 将函数体传递过去, lambda其实就是传递的函数, 只不过是以多态的形式调用的, 再加上参数类型推断.
        list.forEach(System.out::println);
    }

}
